<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    
    <title>GIL全局解释器锁 | 王鹏的技术博客</title>
    
    
        <meta property="og:site_name" content="王鹏的技术博客">
    
    
        <meta property="article:author" content="王 鹏">
    
    
        <link rel="icon" href="/mhexo/img/favicon.ico">
    
    
<link rel="stylesheet" href="/mhexo/css/minireset.min.css">

    
<link rel="stylesheet" href="/mhexo/css/all.min.css">

    
<link rel="stylesheet" href="/mhexo/css/csshake.min.css">

    
<link rel="stylesheet" href="/mhexo/css/hljs/lioshi.css">

    
<link rel="stylesheet" href="/mhexo/css/jquery.fancybox.min.css">

    
<link rel="stylesheet" href="/mhexo/styl/main.css">

    
<script src="/mhexo/js/jquery.min.js"></script>

    
<script src="/mhexo/js/highlight.min.js"></script>

    
<script src="/mhexo/js/jquery.fancybox.min.js"></script>

    
<script src="/mhexo/js/clipboard.min.js"></script>

<meta name="generator" content="Hexo 5.2.0"></head>
<body>
    <header>
  <div class="outer">
    <div class="inner">
      <h1 class="logo-wrap">
        <a>王鹏的技术博客<b><sup>1.1</sup></b></a>
      </h1>
    </div>
    <div class="inner">
      <nav class="main-nav">
        
          <a href="/mhexo/">首页</a>
        
          <a href="/mhexo/archives">归档</a>
        
          <a href="/mhexo/categories">分类</a>
        
          <a href="/mhexo/tags">标签</a>
        
          <a href="/mhexo/friends">友链</a>
        
          <a href="/mhexo/about">关于</a>
        
          <a target="_blank" rel="noopener" href="https://www.baidu.com">百度</a>
        
      </nav>
    </div>
  </div>
</header>
    <div class="content">
        <section class="outer">
    <article>
        <div class="article-title">
    <h2>
        <a href="/mhexo/2020/12/16/GIL%E5%85%A8%E5%B1%80%E8%A7%A3%E9%87%8A%E5%99%A8%E9%94%81/" class="shake shake-little" title="GIL全局解释器锁">
            
            GIL全局解释器锁
        </a>
    </h2>
    <div class="meta_box">
    
        
        
            
                
        
        <div class="meta meta_auth">
            <img src="/mhexo/img/default.png" alt="head" />
            <p>anonymous</p>
        </div>
    
        
        
        <div class="meta meta_date">
            <i class="fas fa-calendar-alt fa-fw" aria-hidden="true"></i>
            <p>发布于：2020年12月16日</p>
        </div>
    
        <div class="meta meta_update">
            <i class="fas fa-edit fa-fw" aria-hidden="true"></i>
            <p>更新于：2020年12月16日</p>
        </div>
    </div>
    

</div>

        <hr>
        <div class="article-entry">
            
            
            
            <h1 id="GIL全局解释器锁"><a href="#GIL全局解释器锁" class="headerlink" title="GIL全局解释器锁"></a>GIL全局解释器锁</h1><h2 id="1-GIL是什么？"><a href="#1-GIL是什么？" class="headerlink" title="1.GIL是什么？"></a>1.GIL是什么？</h2><p>GIL全称Global Interpreter Lock，即全局解释器锁。 作用就是，限制多线程同时执行，保证同一时间内只有一个线程在执行。 GIL并不是Python的特性，它是在实现Python解析器(CPython)时所引入的一个概念。python 与 python解释器是两个概念，切不可混为一谈，也就是说，GIL只存在于使用C语言编写的解释器CPython中。 通俗地说，就是如果你不用Python官方推荐的CPython解释器，而使用其他语言编写的Python解释器（比如 JPython: 运行在Java上的解释器，直接把python代码编译成Java字节码执行 ），就不会有GIL问题。然而因为CPython是大部分环境下默认的Python执行环境。所以在很多人的概念里CPython就是Python，也就想当然的把GIL归结为Python语言的缺陷。所以这里要先明确一点：GIL并不是Python的特性，Python完全可以不依赖于GIL。</p>
<h2 id="2-GIL有什么作用？"><a href="#2-GIL有什么作用？" class="headerlink" title="2.GIL有什么作用？"></a>2.GIL有什么作用？</h2><p>为了更有效的利用多核处理器的性能，就出现了多线程的编程方式，而随之带来的就是线程间数据的一致性和状态同步的完整性。 python为了利用多核，开始支持多线程，但线程是非独立的，所以同一进程里线程是数据共享，当各个线程访问数据资源时会出现竞状态，即数据可能会同时被多个线程占用，造成数据混乱，这就是线程的不安全。而解决多线程之间数据完整性和状态同步最简单的方式就是加锁。GIL能限制多线程同时执行，保证同一时间内只有一个线程在执行。</p>
<h2 id="3-GIL有什么影响？"><a href="#3-GIL有什么影响？" class="headerlink" title="3.GIL有什么影响？"></a>3.GIL有什么影响？</h2><p>GIL无疑就是一把全局排他锁。毫无疑问全局锁的存在会对多线程的效率有不小影响。甚至就几乎等于Python是个单线程的程序。</p>
<h3 id="写一个证明："><a href="#写一个证明：" class="headerlink" title="写一个证明："></a>写一个证明：</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> threading</span><br><span class="line"></span><br><span class="line">num = <span class="number">0</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">change_it</span>(<span class="params">n</span>):</span></span><br><span class="line">    <span class="keyword">global</span> num</span><br><span class="line">    <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">1000000</span>):</span><br><span class="line">        num = num + n</span><br><span class="line">        num = num - n</span><br><span class="line">    print(num)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">threads = [</span><br><span class="line">    threading.Thread(target=change_it, args=(<span class="number">8</span>,)),</span><br><span class="line">    threading.Thread(target=change_it, args=(<span class="number">10</span>,))</span><br><span class="line">]</span><br><span class="line"></span><br><span class="line"><span class="comment">#列表推导式，简单的for</span></span><br><span class="line">[t.start() <span class="keyword">for</span> t <span class="keyword">in</span> threads]</span><br><span class="line"><span class="comment">#[t.join() for t in threads]      #阻塞</span></span><br><span class="line">print(num)  <span class="comment">#多次执行打印结果会发现他的值并不是预想的值，这就是因为python在高并发情况下资源混乱的问题</span></span><br></pre></td></tr></table></figure>

<h2 id="4-如何避免GIL带来的影响？"><a href="#4-如何避免GIL带来的影响？" class="headerlink" title="4.如何避免GIL带来的影响？"></a>4.如何避免GIL带来的影响？</h2><p>方法一：用进程+协程 代替 多线程的方式 在多进程中，由于每个进程都是独立的存在，所以每个进程内的线程都拥有独立的GIL锁，互不影响。但是，由于进程之间是独立的存在，所以进程间通信就需要通过队列的方式来实现。</p>
<h2 id="方法二：更换解释器"><a href="#方法二：更换解释器" class="headerlink" title="方法二：更换解释器"></a>方法二：更换解释器</h2><p>像JPython和IronPython这样的解析器由于实现语言的特性，他们不需要GIL的帮助。然而由于用了Java/C#用于解析器实现，他们也失去了利用社区众多C语言模块有用特性的机会。所以这些解析器也因此一直都比较小众。</p>
<h2 id="一些其他的解释器"><a href="#一些其他的解释器" class="headerlink" title="一些其他的解释器"></a>一些其他的解释器</h2><p>CPython 当我们从Python官方网站下载并安装好Python 2.7后，我们就直接获得了一个官方版本的解释器：CPython。这个解释器是用C语言开发的，所以叫CPython。在命令行下运行python就是启动CPython解释器。</p>
<p>CPython是使用最广的Python解释器。教程的所有代码也都在CPython下执行。</p>
<p>IPython IPython是基于CPython之上的一个交互式解释器，也就是说，IPython只是在交互方式上有所增强，但是执行Python代码的功能和CPython是完全一样的。好比很多国产浏览器虽然外观不同，但内核其实都是调用了IE。</p>
<p>CPython用&gt;&gt;&gt;作为提示符，而IPython用In [序号]:作为提示符。</p>
<p>PyPy PyPy是另一个Python解释器，它的目标是执行速度。PyPy采用JIT技术，对Python代码进行动态编译（注意不是解释），所以可以显著提高Python代码的执行速度。</p>
<p>绝大部分Python代码都可以在PyPy下运行，但是PyPy和CPython有一些是不同的，这就导致相同的Python代码在两种解释器下执行可能会有不同的结果。如果你的代码要放到PyPy下执行，就需要了解PyPy和CPython的不同点。</p>
<p>Jython Jython是运行在Java平台上的Python解释器，可以直接把Python代码编译成Java字节码执行。</p>
<p>IronPython IronPython和Jython类似，只不过IronPython是运行在微软.Net平台上的Python解释器，可以直接把Python代码编译成.Net的字节码。</p>
<h3 id="但是会发生另一些事情："><a href="#但是会发生另一些事情：" class="headerlink" title="但是会发生另一些事情："></a>但是会发生另一些事情：</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> threading</span><br><span class="line"></span><br><span class="line">num = <span class="number">0</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">change_it</span>(<span class="params">n</span>):</span></span><br><span class="line">    <span class="keyword">global</span> num</span><br><span class="line">    <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">1000000</span>):</span><br><span class="line">        num = num + n</span><br><span class="line">        num = num - n</span><br><span class="line">    print(num)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">threads = [</span><br><span class="line">    threading.Thread(target=change_it, args=(<span class="number">8</span>,)),</span><br><span class="line">    threading.Thread(target=change_it, args=(<span class="number">10</span>,))</span><br><span class="line">]</span><br><span class="line"></span><br><span class="line"><span class="comment">#列表推导式，简单的for6</span></span><br><span class="line">[t.start() <span class="keyword">for</span> t <span class="keyword">in</span> threads]</span><br><span class="line">[t.join() <span class="keyword">for</span> t <span class="keyword">in</span> threads]      <span class="comment">#阻塞</span></span><br><span class="line">print(num)</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> time</span><br><span class="line">s1 = time.time()</span><br><span class="line">s2 = [x*<span class="number">2</span> <span class="keyword">for</span> x <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">10000000</span>)]</span><br><span class="line">print(<span class="string">&#x27;运行时间：&#x27;</span>, time.time()-s1)  <span class="comment">#用pypy解释器运行会发现运行时间明显高于python,这便是pypy没有GIL机制，运行的比较慢</span></span><br></pre></td></tr></table></figure>


        </div>
        <div class="article-copyright">
            
    <blockquote>
        <p>
            版权声明：本文为「子曰无衣」的原创文章，博客内容遵循 署名-非商业性使用-相同方式共享 协议。<br>本文永久链接是：https://wangpdizhi.gitee.io/mhexo/2020/12/16/GIL%E5%85%A8%E5%B1%80%E8%A7%A3%E9%87%8A%E5%99%A8%E9%94%81/
        </p>
    </blockquote>


        </div>
    </article>
    

    <section id="toc-div" >
        <ol class="toc"><li class="toc-item toc-level-1"><a class="toc-link" href="#GIL%E5%85%A8%E5%B1%80%E8%A7%A3%E9%87%8A%E5%99%A8%E9%94%81"><span class="toc-text">GIL全局解释器锁</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#1-GIL%E6%98%AF%E4%BB%80%E4%B9%88%EF%BC%9F"><span class="toc-text">1.GIL是什么？</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#2-GIL%E6%9C%89%E4%BB%80%E4%B9%88%E4%BD%9C%E7%94%A8%EF%BC%9F"><span class="toc-text">2.GIL有什么作用？</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#3-GIL%E6%9C%89%E4%BB%80%E4%B9%88%E5%BD%B1%E5%93%8D%EF%BC%9F"><span class="toc-text">3.GIL有什么影响？</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%86%99%E4%B8%80%E4%B8%AA%E8%AF%81%E6%98%8E%EF%BC%9A"><span class="toc-text">写一个证明：</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#4-%E5%A6%82%E4%BD%95%E9%81%BF%E5%85%8DGIL%E5%B8%A6%E6%9D%A5%E7%9A%84%E5%BD%B1%E5%93%8D%EF%BC%9F"><span class="toc-text">4.如何避免GIL带来的影响？</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%96%B9%E6%B3%95%E4%BA%8C%EF%BC%9A%E6%9B%B4%E6%8D%A2%E8%A7%A3%E9%87%8A%E5%99%A8"><span class="toc-text">方法二：更换解释器</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%B8%80%E4%BA%9B%E5%85%B6%E4%BB%96%E7%9A%84%E8%A7%A3%E9%87%8A%E5%99%A8"><span class="toc-text">一些其他的解释器</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E4%BD%86%E6%98%AF%E4%BC%9A%E5%8F%91%E7%94%9F%E5%8F%A6%E4%B8%80%E4%BA%9B%E4%BA%8B%E6%83%85%EF%BC%9A"><span class="toc-text">但是会发生另一些事情：</span></a></li></ol></li></ol></li></ol>
    </section>
    <section id="gohome" style="display: none;"><a>顶</a></section>

    <script>
        function get_top_by_link(link){
            var hnid = "#" + $(link).attr("data");
            if ($(hnid).length > 0){
                return $(hnid).offset().top;
            }else{
                return 0;
            }
        }
        //go to hn
        function gotohn(link){
            $("html,body").animate({scrollTop: get_top_by_link(link) }, 300);
        }
        //页面滚动
        function update(){
            var scrollH = $(window).scrollTop();
            if($(".toc-link")){
                $(".toc-link").each(function(i,link){
                    var mdHeight = get_top_by_link(link);
                    if(mdHeight <= scrollH + 40){
                        //高亮导航菜单
                        $('.toc-link').removeClass('on');
                        $(link).addClass('on');
                    }
                });
            }
            //返回顶部显隐
            if(scrollH < 200){
                $("#gohome").css("display","none");
            }else{
                $("#gohome").css("display","block");
            }
        }
        $(function(){
            //修复部分锚点从属关系
            if($("#toc-div >li").length > 0){
                $("#toc-div >li").appendTo($("#toc-div >ol:first"));
            }
            //返回顶部
            $('#gohome').click(function(){
                $("html,body").animate({scrollTop: 0}, 300);
                return false;
            })
            //遍历锚点
            $(".toc-link").each(function(i,link){
                $(link).attr("data",$(link).attr('href').substring(1));
                $(link).attr("href","javascript:void(0);");
                $(link).attr("onclick","gotohn(this);");
            })
            //绑定滚动事件
            $(window).bind('scroll', update);
            //初始化toc
            var first_toc = $(".toc-link")[0];
            var first_scroll = get_top_by_link(first_toc);
            var window_scroll = $(window).scrollTop();
            if(window_scroll <= first_scroll){
                $(first_toc).addClass('on');
            }
        })
    </script>

</section>
    </div>
    <footer>
    <div class="outer">
        <div class="inner">
            Powered by <a href="http://prowiki.demopage.icu/" target="_blank">ProWiki</a>
            &copy;2020 子曰无衣<br>
            <a target="_blank" rel="noopener" href="http://beian.miit.gov.cn/">冀ICP备00000000号</a>
        </div>
    </div>
</footer>

<script src="/mhexo/js/custom.js"></script>


    <script>onload_content();</script>

</body>
</html>
